/**
 * Copyright (c) 2008, Andrew Carter
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are 
 * permitted provided that the following conditions are met:
 * 
 * Redistributions of source code must retain the above copyright notice, this list of 
 * conditions and the following disclaimer. Redistributions in binary form must reproduce 
 * the above copyright notice, this list of conditions and the following disclaimer in 
 * the documentation and/or other materials provided with the distribution. Neither the 
 * name of Andrew Carter nor the names of contributors may be used to endorse or promote 
 * products derived from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.acarter.scenemonitor;

import java.lang.reflect.InvocationTargetException;
import java.util.logging.Logger;

import javax.swing.UIManager;

import com.acarter.scenemonitor.dialog.MonitorDialog;
import com.acarter.scenemonitor.information.A_MonitorInformationPanel;
import com.jme.renderer.Renderer;
import com.jme.scene.Node;

/**
 * This exposes all the functionality to the user.
 * 
 * @author Andrew Carter
 */
public class SceneMonitor {

	/** Logger name */
	public static final String LOGGER_NAME = "com.acarter.scenemonitor.SceneMonitor";

	/** Logger reference */
	private static final Logger LOGGER = Logger.getLogger(SceneMonitor.LOGGER_NAME);

	/** The one and only instance if this class */
	private static SceneMonitor instance = null;

	/** The dialog displayed to the user */
	private MonitorDialog dialog = null;

	/**
	 * Private constructor.
	 * 
	 * @throws InvocationTargetException
	 * @throws InterruptedException
	 */
	private SceneMonitor() {

		try {
			javax.swing.SwingUtilities.invokeAndWait(new Runnable() {

				public void run() {

					try {

						UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
					}
					catch (Exception e) {

						LOGGER.warning("Could not set cross platform look and feel.");
						e.printStackTrace();
					}

					dialog = new MonitorDialog(null);
				}
			});
		}
		catch (InterruptedException e) {
			e.printStackTrace();
		}
		catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Returns the singleton instance.
	 * 
	 * @return The instance
	 */
	public static SceneMonitor getMonitor() {

		if (instance == null) {
			instance = new SceneMonitor();
		}

		return instance;
	}

	/**
	 * Set the visibility of the dialog.
	 * 
	 * @param show
	 *            True to show it, False to hide it.
	 */
	public void showViewer(final boolean show) {

		javax.swing.SwingUtilities.invokeLater(new Runnable() {

			public void run() {
				dialog.setVisible(show);
			}
		});
	}

	/**
	 * Returns whether the dialog is visible or not.
	 * 
	 * @return boolean True if visible, false otherwise.
	 */
	public boolean isVisible() {

		return dialog.isVisible();
	}

	/**
	 * Called by the host application to refresh the tree view in the dialog.
	 * 
	 * @param tpf
	 *            Time per frame
	 */
	public void updateViewer(final float tpf) {

		javax.swing.SwingUtilities.invokeLater(new Runnable() {

			public void run() {
				dialog.doUpdate(tpf);
			}
		});
	}

	/**
	 * Called by the host application to render from the dialog.
	 * 
	 * @param tpf
	 *            Time per frame
	 */
	public void renderViewer(final Renderer renderer) {

		// This needs to be done in the GL thread, so no swing invoke later calls used here
		dialog.render(renderer);
	}

	/**
	 * Defines the amount of time between tree updates.
	 * 
	 * @param seconds
	 */
	public void setViewerUpdateInterval(final float seconds) {

		javax.swing.SwingUtilities.invokeLater(new Runnable() {

			public void run() {
				dialog.setUpdateInterval(seconds);
			}
		});
	}

	/**
	 * Adds a node to the list of nodes the user may select using the node name.
	 * 
	 * @param node
	 */
	public void registerNode(Node node) {

		registerNode(node, node.getName());
	}

	/**
	 * Adds a node to the list of nodes the user may select.
	 * 
	 * @param node
	 * @param displayName
	 *            The name to use in the list
	 */
	public void registerNode(final Node node, final String displayName) {

		javax.swing.SwingUtilities.invokeLater(new Runnable() {

			public void run() {
				dialog.registerNode(node, displayName);
			}
		});
	}

	/**
	 * Removes a node from the list of node the user may select.
	 * 
	 * @param node
	 */
	public void unregisterNode(final Node node) {

		javax.swing.SwingUtilities.invokeLater(new Runnable() {

			public void run() {
				dialog.unregisterNode(node);
			}
		});
	}

	/**
	 * Selects the given object in the tree.
	 * 
	 * @param object
	 *            The object to select.
	 */
	public void selectSceneObject(final Object object) {

		javax.swing.SwingUtilities.invokeLater(new Runnable() {

			public void run() {
				dialog.selectObject(object);
			}
		});

	}

	/**
	 * Allows the addition of custom descriptor definitions.
	 * 
	 * @param classType
	 * @param descriptor
	 */
	public A_MonitorInformationPanel getMonitorInformationPanel() {

		return dialog.getInformationPanel();
	}
}
